# install.packages("tidyverse");
# install.packages("rgdal");
library(tidyverse)
require("maps")
library(geosphere)
library(stringr)
library(rgdal)
library(caret)
library(lubridate)
library(maptools)
if (!require(ggmap)) { install.packages('ggmap'); require(ggmap) }
library(ggmap)
path.to.csv <- '~/Downloads/Seattle_Police_Department_911_Incident_Response (1).csv'
spd.911 <- read.csv(path.to.csv, header = TRUE)
spd.911 <- spd.911 %>% 
             rowwise() %>% 
             mutate(dist=distVincentyEllipsoid(c(Longitude, Latitude), c(here_long, here_lat)))              
nrow(spd.911)
[1] 257011
descriptions <- c("STRONG ARM ROBBERY", "PERSON WITH A WEAPON (NOT GUN)", "HAZARDS", "HARASSMENT, THREATS", "FIGHT DISTURBANCE", "CRISIS COMPLAINT - GENERAL", "ARMED ROBBERY")
# Removes Specifically Harassment by Telephone and Writing, as well as other non-scary crimes
data.ped <- spd.911 %>% filter(str_detect(Event.Clearance.Description, paste(descriptions, collapse="|"))) %>% filter(!str_detect(Event.Clearance.Description, "HARASSMENT, THREATS - BY TELEPHONE, WRITING")) %>% filter(!str_detect(Event.Clearance.Description, "HARBOR DEBRIS, NAVIGATIONAL HAZARDS"))
nrow(data.ped)
[1] 15606
data.here <- data.ped %>% filter(dist < 2600)
data.w.at.scene <- filter(data.here, !is.na(at_scene_time_date))
data <- data.w.at.scene
nrow(data)
[1] 722
# View(data)
write.csv(data, '2016-2017-Clean.csv')

Clustering crimes by Time of Day

Time is a huge factor when discussing pedestrian safety in an error, or so we’re told. Common wisdom states that night time is more dangerous than day time, but is this even true? When do crimes get reported, and how does that change where the centers of crime are located. Here we look at a year’s worth of SPD data in order to gain some insight.

data <- read.csv('2016-2017-Clean.csv', header = TRUE)
# View(data)
data <- filter(data, !str_detect(Event.Clearance.Description, "HARBOR - DEBRIS, NAVIGATIONAL HAZARDS"))
nrow(data)
ggmap(seattle) +
   geom_point(data = data, aes(x = Longitude, y = Latitude), colour = "red", alpha = 0.75)

First of, we want to make sure we use as much data as possible. Using reports for all years tract would be ideal, but that data set is too large to handle easily. Instead, we’d like to use just the past year’s worth, from November 1st, 2016, all the way to October 31, 2017. That gives us a full year’s worth of data to look at, and its far enough in the past from today that we can ensure most, if not all, incidences will be closed (and therefore included in the data set).

Before we go any further though, it is important we determine whether or not the time of year has any meaningful effect on the number of observations we have to work with. If several months have much higher crime rates than others, it may skew results of any analysis we do. With that in mind, let’s take a look at the distribution of crimes for each month in the last year:

k

    Kruskal-Wallis rank sum test

data:  Freq by Var1
Kruskal-Wallis chi-squared = 11, df = 11, p-value = 0.4433

As we can see, there isn’t much varience in the frequency of reported crimes in our area for the past year.

freq_by_desc <- table(droplevels(data$Event.Clearance.Description))
# View(freq_by_desc)
ggplot(as.data.frame(freq_by_desc), 
       aes(x = Var1, y = Freq)) +
       geom_bar(stat = 'identity') +# create bar plot
    coord_flip()

#Traffic related calls, suspicious circumstances, and disturbances are the the most significant threats to pedestrations
        
ggmap(seattle) +
  geom_point(data = data, aes(x = Longitude, y = Latitude, group = Event.Clearance.Description, color = Event.Clearance.Description), alpha = 0.5, size = 10) +
  facet_wrap(~ Event.Clearance.Description) +
  theme(axis.ticks = element_blank(), 
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        strip.text = element_text(size=50),
        legend.position = "none"
        )

# selecting just ID and location data
df_loc <- data %>% dplyr::select(CAD.CDW.ID, Longitude, Latitude)
# figuring out number of clusters
wss <- c()
# clusters 1 to 15
for (i in 1:15) {
  wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
}
plot(1:15, wss, type="b", xlab="Number of Clusters",
  ylab="Within groups sum of squares")

# fitting model
fit <- kmeans(df_loc, 10)
fit$centers # look at cluster sizes and means. want clusters to be about equal size
   CAD.CDW.ID Longitude Latitude
1     1966835 -122.3188 47.65906
2     2093969 -122.3142 47.65982
3     2116300 -122.3129 47.66095
4     1899308 -122.3154 47.66025
5     2046956 -122.3160 47.65922
6     2071185 -122.3156 47.66114
7     1864428 -122.3118 47.66149
8     2022152 -122.3172 47.66033
9     1994531 -122.3159 47.66109
10    1932836 -122.3171 47.66133
fit$cluster
  [1]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [40]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [79]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[118]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[157]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4 10 10 10 10 10 10 10 10
[196] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[235] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[274] 10 10 10 10 10 10 10 10 10  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[313]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[352]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[391]  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[430]  9  9  9  9  9  9  9  9  9  9  9  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[469]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[508]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
[547]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[586]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[625]  6  6  6  6  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
[664]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3  3  3  3  3  3
[703]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
[742]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
cluster.size <- data.frame(1:10, fit$size)
cluster.size
ggplot(data = cluster.size, aes(x = X1.10, y = fit.size)) +
  geom_bar(stat = 'identity')

ggplot()

ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
aggregate(df_loc, by=list(fit$cluster), FUN=mean)
df_loc
# adding data back into dataframe 
# df_loc <- df_loc %>% mutate(cluster = fit$cluster) 
# View(data)
by_month <- table(data$event_clearance_month)
by_month <- table(data$event_clearance_month)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiRXJyb3I6IGF0dGVtcHQgdG8gdXNlIHplcm8tbGVuZ3RoIHZhcmlhYmxlIG5hbWVcbiJ9 -->

Error: attempt to use zero-length variable name ```

# hundred block vs TOD
  
by_hr <- table(data$event_clearance_hr)
by_hr

  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23 
 38  28  31  52  20  16  17  15  14  16  12  36  20  32  36  39  43  24  25 115  21  38  40  37 
ggplot(as.data.frame(by_hr), aes(x = Var1, y = Freq)) + 
  geom_point() +
  xlab('hour of day')

ggplot(data, aes(x = event_clearance_ts, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

ggplot(data, aes(x = Hundred.Block.Location, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

  
# selecting just ID and location data
df_loc <- data.w.at.scene %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
Error in eval(lhs, parent, parent) : object 'data.w.at.scene' not found
#some useful functions for performing clustering
#extract the lat and long from a dataframe, and run kmeans on it
# x = one of our dataframes
# clusters = how many centers you want kmeans to work with when clustering
fit.clusters <- function(x, clusters) {
  # selecting just ID and location data
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  # fitting model
  fit <- kmeans(df_loc, clusters)
  fit$centers # look at cluster sizes and means. want clusters to be about equal size
  return(fit)
}
#make a plot that will tell you how many clusters might work for a given dataframe
# x = a dataframe
# max = the maximum number of clusters you want to try
find.num.clusters <- function(x, max) {
  if(max > nrow(x)) { stop('Cannot fit more clusters than there are rows in dataframe')}
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  wss = c()
  for (i in 1:max) {
    wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
  }
  plot(1:max, wss, type="b", xlab="Number of Clusters",
     ylab="Within groups sum of squares")
}
#plot the number of observations in each cluster
# x = a fit object returned from kmeans() or the fit.clusters() function above
plot.cluster.sizes <- function(x) {
  cluster.size <- data.frame(data.frame('clusters' = 1:nrow(x$centers), x$size))
  ggplot(data = cluster.size, aes(x = clusters, y = x.size)) +
  geom_bar(stat = 'identity')
}

Clustering by time of day

morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.28889
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 74
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 176
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

#take out general crisis complaint - general
data <- filter(data, Event.Clearance.Description != 'CRISIS COMPLAINT - GENERAL')
morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.69318
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] HAZARDS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] HARASSMENT, THREATS FIGHT DISTURBANCE  
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] STRONG ARM ROBBERY
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 48
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 107
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJSIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cH0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKTsKIyBpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpOwpsaWJyYXJ5KHRpZHl2ZXJzZSkKcmVxdWlyZSgibWFwcyIpCmxpYnJhcnkoZ2Vvc3BoZXJlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KG1hcHRvb2xzKQppZiAoIXJlcXVpcmUoZ2dtYXApKSB7IGluc3RhbGwucGFja2FnZXMoJ2dnbWFwJyk7IHJlcXVpcmUoZ2dtYXApIH0KbGlicmFyeShnZ21hcCkKcGF0aC50by5jc3YgPC0gJ34vRG93bmxvYWRzL1NlYXR0bGVfUG9saWNlX0RlcGFydG1lbnRfOTExX0luY2lkZW50X1Jlc3BvbnNlICgxKS5jc3YnCnNwZC45MTEgPC0gcmVhZC5jc3YocGF0aC50by5jc3YsIGhlYWRlciA9IFRSVUUpCgpzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5EYXRlLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkKc3BkLjkxMSRjbGVhcmFuY2VfZGF0ZV9kYXRlID0gYXMuRGF0ZShzcGQuOTExJGNsZWFyYW5jZV9kYXRlX3RzKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cyA9IGFzLlBPU0lYY3Qoc3RycHRpbWUoc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuRGF0ZSwgIiVtLyVkLyVZICVJOiVNOiVTICVwIikpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RhdGUgPSBhcy5EYXRlKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV9tb250aCA9IG1vbnRoKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RheSA9IHdlZWtkYXlzKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RhdGUpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2hyID0gaG91cih5bWRfaG1zKGFzLmNoYXJhY3RlcihzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cykpKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV9tbiA9IG1pbnV0ZSh5bWRfaG1zKGFzLmNoYXJhY3RlcihzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV90cykpKQpzcGQuOTExJEluaXRpYWwuVHlwZS5Hcm91cCA9IGZhY3RvcihzcGQuOTExJEluaXRpYWwuVHlwZS5Hcm91cCkKc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuR3JvdXAgPSBmYWN0b3Ioc3BkLjkxMSRFdmVudC5DbGVhcmFuY2UuR3JvdXApCnNwZC45MTEkWm9uZS5CZWF0ID0gZmFjdG9yKHNwZC45MTEkWm9uZS5CZWF0KQpzcGQuOTExJERpc3RyaWN0LlNlY3RvciA9IGZhY3RvcihzcGQuOTExJERpc3RyaWN0LlNlY3RvcikKc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF5ID0gZmFjdG9yKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX2RheSkKCnNwZC45MTEkYXRfc2NlbmVfdGltZV90cyA9IGFzLlBPU0lYY3Qoc3RycHRpbWUoc3BkLjkxMSRBdC5TY2VuZS5UaW1lLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkgI2NvbnZlcnRpbmcgdGltZSBmcm9tIFN0cmluZyB0byBkYXRlIGFuZCB0aW1lIHJlcHJlc2VudGF0aW9uIChQT1NJWGN0KQpzcGQuOTExJGF0X3NjZW5lX3RpbWVfaHIgPSBob3VyKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkYXRfc2NlbmVfdGltZV90cykpKQpzcGQuOTExJGF0X3NjZW5lX3RpbWVfZGF0ZSA9IGFzLkRhdGUoc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzKQpzcGQuOTExJHRpbWVfdW50aWxfZXZlbnRfY2xlYXIgPSBhcy5udW1lcmljKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzIC0gc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzKQoKCgojIHBhdGggdG8gdGhlIEZPTERFUiB3aXRoIHRoZSAuc2hwIGZpbGUgaW4gaXQuIHRoZSBzZWNvbmQgcGFyYW0gaXMgdGhlIG5hbWUgb2YgdGhlIC5zaHAgZmlsZQojIHNlYXR0bGUgPC0gcmVhZE9HUihkc24gPSBwYXRoLmV4cGFuZCgifi9kb2N1bWVudHMvSU5GTzM3MC9wcm9qZWN0LXRlYW1uYW1lLXYyL21hcHMtYXBpLXRlc3QiKSwgbGF5ZXIgPSAiU2VhdHRsZV9DaXR5X0xpbWl0cyIpCgojIHVzYSA8LSBtYXBfZGF0YSgic3RhdGUiKQojIGRhdGEgPC0gbWVyZ2UodXNhLCBzcGQuOTExKQojIFJlZCBTcXVhcmUgY29vcmRpbmF0ZXMKaGVyZV9sb25nIDwtICAtMTIyLjMwOTUKaGVyZV9sYXQgPC0gNDcuNjU2MAoKc2VhdHRsZSA9IGdldF9tYXAobG9jYXRpb24gPSBjKGhlcmVfbG9uZywgaGVyZV9sYXQpLCB6b29tID0gMTMsIG1hcHR5cGUgPSAncm9hZG1hcCcpCgpgYGAKCgpgYGB7cn0Kc3BkLjkxMSA8LSBzcGQuOTExICU+JSAKICAgICAgICAgICAgIHJvd3dpc2UoKSAlPiUgCiAgICAgICAgICAgICBtdXRhdGUoZGlzdD1kaXN0VmluY2VudHlFbGxpcHNvaWQoYyhMb25naXR1ZGUsIExhdGl0dWRlKSwgYyhoZXJlX2xvbmcsIGhlcmVfbGF0KSkpICAgICAgICAgICAgICAKbnJvdyhzcGQuOTExKQoKZGVzY3JpcHRpb25zIDwtIGMoIlNUUk9ORyBBUk0gUk9CQkVSWSIsICJQRVJTT04gV0lUSCBBIFdFQVBPTiAoTk9UIEdVTikiLCAiSEFaQVJEUyIsICJIQVJBU1NNRU5ULCBUSFJFQVRTIiwgIkZJR0hUIERJU1RVUkJBTkNFIiwgIkNSSVNJUyBDT01QTEFJTlQgLSBHRU5FUkFMIiwgIkFSTUVEIFJPQkJFUlkiKQoKIyBSZW1vdmVzIFNwZWNpZmljYWxseSBIYXJhc3NtZW50IGJ5IFRlbGVwaG9uZSBhbmQgV3JpdGluZywgYXMgd2VsbCBhcyBvdGhlciBub24tc2NhcnkgY3JpbWVzCmRhdGEucGVkIDwtIHNwZC45MTEgJT4lIGZpbHRlcihzdHJfZGV0ZWN0KEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiwgcGFzdGUoZGVzY3JpcHRpb25zLCBjb2xsYXBzZT0ifCIpKSkgJT4lIGZpbHRlcighc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sICJIQVJBU1NNRU5ULCBUSFJFQVRTIC0gQlkgVEVMRVBIT05FLCBXUklUSU5HIikpICU+JSBmaWx0ZXIoIXN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCAiSEFSQk9SIERFQlJJUywgTkFWSUdBVElPTkFMIEhBWkFSRFMiKSkKbnJvdyhkYXRhLnBlZCkKCmRhdGEuaGVyZSA8LSBkYXRhLnBlZCAlPiUgZmlsdGVyKGRpc3QgPCAyNjAwKQoKZGF0YS53LmF0LnNjZW5lIDwtIGZpbHRlcihkYXRhLmhlcmUsICFpcy5uYShhdF9zY2VuZV90aW1lX2RhdGUpKQpkYXRhIDwtIGRhdGEudy5hdC5zY2VuZQpucm93KGRhdGEpCiMgVmlldyhkYXRhKQoKd3JpdGUuY3N2KGRhdGEsICcyMDE2LTIwMTctQ2xlYW4uY3N2JykKYGBgCiNDbHVzdGVyaW5nIGNyaW1lcyBieSBUaW1lIG9mIERheQoKVGltZSBpcyBhIGh1Z2UgZmFjdG9yIHdoZW4gZGlzY3Vzc2luZyBwZWRlc3RyaWFuIHNhZmV0eSBpbiBhbiBlcnJvciwgb3Igc28gd2UncmUgdG9sZC4gQ29tbW9uIHdpc2RvbSBzdGF0ZXMgdGhhdCBuaWdodCB0aW1lIGlzIG1vcmUgZGFuZ2Vyb3VzIHRoYW4gZGF5IHRpbWUsIGJ1dCBpcyB0aGlzIGV2ZW4gdHJ1ZT8gV2hlbiBkbyBjcmltZXMgZ2V0IHJlcG9ydGVkLCBhbmQgaG93IGRvZXMgdGhhdCBjaGFuZ2Ugd2hlcmUgdGhlIGNlbnRlcnMgb2YgY3JpbWUgYXJlIGxvY2F0ZWQuIEhlcmUgd2UgbG9vayBhdCBhIHllYXIncyB3b3J0aCBvZiBTUEQgZGF0YSBpbiBvcmRlciB0byBnYWluIHNvbWUgaW5zaWdodC4KYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoJzIwMTYtMjAxNy1DbGVhbi5jc3YnLCBoZWFkZXIgPSBUUlVFKQojIFZpZXcoZGF0YSkKZGF0YSA8LSBmaWx0ZXIoZGF0YSwgIXN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCAiSEFSQk9SIC0gREVCUklTLCBOQVZJR0FUSU9OQUwgSEFaQVJEUyIpKQpucm93KGRhdGEpCmdnbWFwKHNlYXR0bGUpICsKICAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGNvbG91ciA9ICJyZWQiLCBhbHBoYSA9IDAuNzUpCgpgYGAKCkZpcnN0IG9mLCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSB3ZSB1c2UgYXMgbXVjaCBkYXRhIGFzIHBvc3NpYmxlLiBVc2luZyByZXBvcnRzIGZvciBhbGwgeWVhcnMgdHJhY3Qgd291bGQgYmUgaWRlYWwsIGJ1dCB0aGF0IGRhdGEgc2V0IGlzIHRvbyBsYXJnZSB0byBoYW5kbGUgZWFzaWx5LiBJbnN0ZWFkLCB3ZSdkIGxpa2UgdG8gdXNlIGp1c3QgdGhlIHBhc3QgeWVhcidzIHdvcnRoLCBmcm9tIE5vdmVtYmVyIDFzdCwgMjAxNiwgYWxsIHRoZSB3YXkgdG8gT2N0b2JlciAzMSwgMjAxNy4gVGhhdCBnaXZlcyB1cyBhIGZ1bGwgeWVhcidzIHdvcnRoIG9mIGRhdGEgdG8gbG9vayBhdCwgYW5kIGl0cyBmYXIgZW5vdWdoIGluIHRoZSBwYXN0IGZyb20gdG9kYXkgdGhhdCB3ZSBjYW4gZW5zdXJlIG1vc3QsIGlmIG5vdCBhbGwsIGluY2lkZW5jZXMgd2lsbCBiZSBjbG9zZWQgKGFuZCB0aGVyZWZvcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGEgc2V0KS4KCkJlZm9yZSB3ZSBnbyBhbnkgZnVydGhlciB0aG91Z2gsIGl0IGlzIGltcG9ydGFudCB3ZSBkZXRlcm1pbmUgd2hldGhlciBvciBub3QgdGhlIHRpbWUgb2YgeWVhciBoYXMgYW55IG1lYW5pbmdmdWwgZWZmZWN0IG9uIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIHdlIGhhdmUgdG8gd29yayB3aXRoLiBJZiBzZXZlcmFsIG1vbnRocyBoYXZlIG11Y2ggaGlnaGVyIGNyaW1lIHJhdGVzIHRoYW4gb3RoZXJzLCBpdCBtYXkgc2tldyByZXN1bHRzIG9mIGFueSBhbmFseXNpcyB3ZSBkby4gV2l0aCB0aGF0IGluIG1pbmQsIGxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgY3JpbWVzIGZvciBlYWNoIG1vbnRoIGluIHRoZSBsYXN0IHllYXI6CmBgYHtyfQojY2hlY2sgZnJlcXVlbmN5IGJ5IG1vbnRoCmJ5Lm1vbnRoIDwtIHRhYmxlKGRhdGEkZXZlbnRfY2xlYXJhbmNlX21vbnRoKQojIGRhdGEuZnJhbWUoYnkubW9udGgpCnQoYnkubW9udGgpCmNvcigxOjEyLCBkYXRhLmZyYW1lKGJ5Lm1vbnRoKSRGcmVxKQoKayA8LSBrcnVza2FsLnRlc3QoRnJlcSB+IFZhcjEsIGJ5Lm1vbnRoKQprCgpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShieS5tb250aCksIAogICAgICAgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSkpICsKICAgICAgIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQpgYGAKQXMgd2UgY2FuIHNlZSwgdGhlcmUgaXNuJ3QgbXVjaCB2YXJpZW5jZSBpbiB0aGUgZnJlcXVlbmN5IG9mIHJlcG9ydGVkIGNyaW1lcyBpbiBvdXIgYXJlYSBmb3IgdGhlIHBhc3QgeWVhci4gCmBgYHtyfQpmcmVxX2J5X2Rlc2MgPC0gdGFibGUoZHJvcGxldmVscyhkYXRhJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikpCgpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShmcmVxX2J5X2Rlc2MpLCAKICAgICAgIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEpKSArCiAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKyMgY3JlYXRlIGJhciBwbG90CiAgICBjb29yZF9mbGlwKCkKCiNUcmFmZmljIHJlbGF0ZWQgY2FsbHMsIHN1c3BpY2lvdXMgY2lyY3Vtc3RhbmNlcywgYW5kIGRpc3R1cmJhbmNlcyBhcmUgdGhlIHRoZSBtb3N0IHNpZ25pZmljYW50IHRocmVhdHMgdG8gcGVkZXN0cmF0aW9ucwoKICAgICAgICAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIwLCBmaWcud2lkdGg9MjB9CmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlLCBncm91cCA9IEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiwgY29sb3IgPSBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEwKSArCiAgZmFjZXRfd3JhcCh+IEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikgKwogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01MCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgICAgICAgKQpgYGAKCmBgYHtyfQojIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCmRmX2xvYyA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExvbmdpdHVkZSwgTGF0aXR1ZGUpCgojIGZpZ3VyaW5nIG91dCBudW1iZXIgb2YgY2x1c3RlcnMKd3NzIDwtIGMoKQojIGNsdXN0ZXJzIDEgdG8gMTUKZm9yIChpIGluIDE6MTUpIHsKICB3c3NbaV0gPC0gc3VtKGttZWFucyhkZl9sb2MsIGNlbnRlcnM9aSkkd2l0aGluc3MpCn0KcGxvdCgxOjE1LCB3c3MsIHR5cGU9ImIiLCB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMiLAogIHlsYWI9IldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQoKIyBmaXR0aW5nIG1vZGVsCmZpdCA8LSBrbWVhbnMoZGZfbG9jLCAxMCkKZml0JGNlbnRlcnMgIyBsb29rIGF0IGNsdXN0ZXIgc2l6ZXMgYW5kIG1lYW5zLiB3YW50IGNsdXN0ZXJzIHRvIGJlIGFib3V0IGVxdWFsIHNpemUKZml0JGNsdXN0ZXIKY2x1c3Rlci5zaXplIDwtIGRhdGEuZnJhbWUoMToxMCwgZml0JHNpemUpCmNsdXN0ZXIuc2l6ZQoKZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gWDEuMTAsIHkgPSBmaXQuc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKZ2dwbG90KCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCmFnZ3JlZ2F0ZShkZl9sb2MsIGJ5PWxpc3QoZml0JGNsdXN0ZXIpLCBGVU49bWVhbikKCmRmX2xvYwoKIyBhZGRpbmcgZGF0YSBiYWNrIGludG8gZGF0YWZyYW1lIAojIGRmX2xvYyA8LSBkZl9sb2MgJT4lIG11dGF0ZShjbHVzdGVyID0gZml0JGNsdXN0ZXIpIAoKIyBWaWV3KGRhdGEpCmBgYAoKYGBge3J9CiMgZGlzdHJpYnV0aW9uIG9mIGNyaW1lcyBieSBtb250aApieV9tb250aCA8LSB0YWJsZShkYXRhJGV2ZW50X2NsZWFyYW5jZV9tb250aCkKYnlfbW9udGgKYGBgCgpgYGB7cn0KIyBodW5kcmVkIGJsb2NrIHZzIFRPRAogIApieV9ociA8LSB0YWJsZShkYXRhJGV2ZW50X2NsZWFyYW5jZV9ocikKYnlfaHIKZ2dwbG90KGFzLmRhdGEuZnJhbWUoYnlfaHIpLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoJ2hvdXIgb2YgZGF5JykKCgoKZ2dwbG90KGRhdGEsIGFlcyh4ID0gZXZlbnRfY2xlYXJhbmNlX3RzLCB5ID0gdGltZV91bnRpbF9ldmVudF9jbGVhcikpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpCgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBIdW5kcmVkLkJsb2NrLkxvY2F0aW9uLCB5ID0gdGltZV91bnRpbF9ldmVudF9jbGVhcikpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpCiAgCgojIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCmRmX2xvYyA8LSBkYXRhLncuYXQuc2NlbmUgJT4lIGRwbHlyOjpzZWxlY3QoQ0FELkNEVy5JRCwgTGF0aXR1ZGUsIExvbmdpdHVkZSkKCiMgZmlndXJpbmcgb3V0IG51bWJlciBvZiBjbHVzdGVycwp3c3MgPC0gYygpCiMgY2x1c3RlcnMgMSB0byAxNQpmb3IgKGkgaW4gMToxNSkgewogIHdzc1tpXSA8LSBzdW0oa21lYW5zKGRmX2xvYywgY2VudGVycz1pKSR3aXRoaW5zcykKfQpwbG90KDE6MTUsIHdzcywgdHlwZT0iYiIsIHhsYWI9Ik51bWJlciBvZiBDbHVzdGVycyIsCiAgeWxhYj0iV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpCgojIGZpdHRpbmcgbW9kZWwKZml0IDwtIGttZWFucyhkZl9sb2MsIDUpCmZpdCRjZW50ZXJzICMgbG9vayBhdCBjbHVzdGVyIHNpemVzIGFuZCBtZWFucy4gd2FudCBjbHVzdGVycyB0byBiZSBhYm91dCBlcXVhbCBzaXplCmZpdCRjbHVzdGVyCmNsdXN0ZXIuc2l6ZSA8LSBkYXRhLmZyYW1lKDE6NSwgZml0JHNpemUpCmNsdXN0ZXIuc2l6ZQoKZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gWDEuNSwgeSA9IGZpdC5zaXplKSkgKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQpnZ3Bsb3QoKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKYWdncmVnYXRlKGRmX2xvYywgYnk9bGlzdChmaXQkY2x1c3RlciksIEZVTj1tZWFuKQoKZGZfbG9jCmBgYAoKYGBge3J9CiNzb21lIHVzZWZ1bCBmdW5jdGlvbnMgZm9yIHBlcmZvcm1pbmcgY2x1c3RlcmluZwoKI2V4dHJhY3QgdGhlIGxhdCBhbmQgbG9uZyBmcm9tIGEgZGF0YWZyYW1lLCBhbmQgcnVuIGttZWFucyBvbiBpdAojIHggPSBvbmUgb2Ygb3VyIGRhdGFmcmFtZXMKIyBjbHVzdGVycyA9IGhvdyBtYW55IGNlbnRlcnMgeW91IHdhbnQga21lYW5zIHRvIHdvcmsgd2l0aCB3aGVuIGNsdXN0ZXJpbmcKZml0LmNsdXN0ZXJzIDwtIGZ1bmN0aW9uKHgsIGNsdXN0ZXJzKSB7CiAgIyBzZWxlY3RpbmcganVzdCBJRCBhbmQgbG9jYXRpb24gZGF0YQogIGRmX2xvYyA8LSB4ICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExhdGl0dWRlLCBMb25naXR1ZGUpCgogICMgZml0dGluZyBtb2RlbAogIGZpdCA8LSBrbWVhbnMoZGZfbG9jLCBjbHVzdGVycykKICBmaXQkY2VudGVycyAjIGxvb2sgYXQgY2x1c3RlciBzaXplcyBhbmQgbWVhbnMuIHdhbnQgY2x1c3RlcnMgdG8gYmUgYWJvdXQgZXF1YWwgc2l6ZQogIHJldHVybihmaXQpCn0KCiNtYWtlIGEgcGxvdCB0aGF0IHdpbGwgdGVsbCB5b3UgaG93IG1hbnkgY2x1c3RlcnMgbWlnaHQgd29yayBmb3IgYSBnaXZlbiBkYXRhZnJhbWUKIyB4ID0gYSBkYXRhZnJhbWUKIyBtYXggPSB0aGUgbWF4aW11bSBudW1iZXIgb2YgY2x1c3RlcnMgeW91IHdhbnQgdG8gdHJ5CmZpbmQubnVtLmNsdXN0ZXJzIDwtIGZ1bmN0aW9uKHgsIG1heCkgewogIGlmKG1heCA+IG5yb3coeCkpIHsgc3RvcCgnQ2Fubm90IGZpdCBtb3JlIGNsdXN0ZXJzIHRoYW4gdGhlcmUgYXJlIHJvd3MgaW4gZGF0YWZyYW1lJyl9CiAgZGZfbG9jIDwtIHggJT4lIGRwbHlyOjpzZWxlY3QoQ0FELkNEVy5JRCwgTGF0aXR1ZGUsIExvbmdpdHVkZSkKICB3c3MgPSBjKCkKICBmb3IgKGkgaW4gMTptYXgpIHsKICAgIHdzc1tpXSA8LSBzdW0oa21lYW5zKGRmX2xvYywgY2VudGVycz1pKSR3aXRoaW5zcykKICB9CiAgcGxvdCgxOm1heCwgd3NzLCB0eXBlPSJiIiwgeGxhYj0iTnVtYmVyIG9mIENsdXN0ZXJzIiwKICAgICB5bGFiPSJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikKfQoKI3Bsb3QgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjbHVzdGVyCiMgeCA9IGEgZml0IG9iamVjdCByZXR1cm5lZCBmcm9tIGttZWFucygpIG9yIHRoZSBmaXQuY2x1c3RlcnMoKSBmdW5jdGlvbiBhYm92ZQpwbG90LmNsdXN0ZXIuc2l6ZXMgPC0gZnVuY3Rpb24oeCkgewogIGNsdXN0ZXIuc2l6ZSA8LSBkYXRhLmZyYW1lKGRhdGEuZnJhbWUoJ2NsdXN0ZXJzJyA9IDE6bnJvdyh4JGNlbnRlcnMpLCB4JHNpemUpKQogIGdncGxvdChkYXRhID0gY2x1c3Rlci5zaXplLCBhZXMoeCA9IGNsdXN0ZXJzLCB5ID0geC5zaXplKSkgKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQp9CmBgYAojI0NsdXN0ZXJpbmcgYnkgdGltZSBvZiBkYXkKYGBge3J9Cm1vcm5pbmcgPC0gZmlsdGVyKGRhdGEsIDYgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDEwICkKbWlkLmRheSA8LSAgZmlsdGVyKGRhdGEsIDEwIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxNCApCmFmdGVybm9vbiA8LSAgZmlsdGVyKGRhdGEsIDE0IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxOCApCmV2ZW5pbmcgPC0gIGZpbHRlcihkYXRhLCAxOCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMjIgKQpuaWdodCA8LSAgZmlsdGVyKGRhdGEsIDIyIDw9IGF0X3NjZW5lX3RpbWVfaHIgfCBhdF9zY2VuZV90aW1lX2hyIDwgMiApCmVhcmx5Lm1vcm5pbmcgPC0gIGZpbHRlcihkYXRhLCAyIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCA2ICkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWlkLmRheSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFmdGVybm9vbiwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGV2ZW5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBuaWdodCwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGVhcmx5Lm1vcm5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmxlbmd0aHMgPC0gYyhucm93KG1vcm5pbmcpLCBucm93KG1pZC5kYXkpLCBucm93KGFmdGVybm9vbiksIG5yb3coZXZlbmluZyksIG5yb3cobmlnaHQpLCBucm93KGVhcmx5Lm1vcm5pbmcpKQpuYW1lcyA8LSBjKCdNb3JuaW5nXG42OjAwIC0gOTo1OScsICdNaWQtZGF5XG4xMDowMCAtIDE6NTknLCAnQWZ0ZXJub29uXG4yOjAwIC0gNTo1OScsICdFdmVuaW5nXG42OjAwIC0gOTo1OScsICdOaWdodFxuMTA6MDAgLSAxOjU5JywgJ0Vhcmx5IE1vcm5pbmdcbjI6MDAgLSA1OjU5JykKYnkudG9kIDwtIGRhdGEuZnJhbWUoJ1RPRCcgPSBuYW1lcywgJ0NvdW50LkNyaW1lcycgPSBsZW5ndGhzKQpieS50b2QkVE9EID0gZmFjdG9yKGJ5LnRvZCRUT0QsIGxldmVscyA9IGJ5LnRvZCRUT0QpCgpnZ3Bsb3QoYnkudG9kLCBhZXMoeCA9IFRPRCwgeSA9IENvdW50LkNyaW1lcykpICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gJ2lkZW50aXR5JykKCiMgZmluZCB0aGUgbW9kZSBvZiBudW1lcmljL2NoYXJhY3RlciBkYXRhCk1vZGUgPC0gZnVuY3Rpb24oeCkgewogIHV4IDwtIHVuaXF1ZSh4KQogIHRhYiA8LSB0YWJ1bGF0ZShtYXRjaCh4LCB1eCkpOyB1eFt0YWIgPT0gbWF4KHRhYildCn0KCnRvZC5tZWFuIDwtIG1lYW4oZGF0YSRhdF9zY2VuZV90aW1lX2hyKQp0b2QubWVkIDwtIG1lZGlhbihkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCnRvZC5tZWFuCnRvZC5tZWQKTW9kZShkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCgojV2hhdCBpcyB0aGUgbW9zdCBjb21tb24gY3JpbWUgY29tbWl0dGVkIGF0IGVhY2ggcGVyaW9kPwpNb2RlKG1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKG1pZC5kYXkkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGFmdGVybm9vbiRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoZXZlbmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUobmlnaHQkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGVhcmx5Lm1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQoKI2ZpdCBrbWVhbnMgY2x1c3RlcmluZyB0byBlYWNoIHRpbWUgcGVyaW9kLgpucm93KG1vcm5pbmcpCmZpbmQubnVtLmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobWlkLmRheSwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKbnJvdyhhZnRlcm5vb24pCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhldmVuaW5nLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhldmVuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhuaWdodCwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobmlnaHQsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmBgYAoKYGBge3J9CiN0YWtlIG91dCBnZW5lcmFsIGNyaXNpcyBjb21wbGFpbnQgLSBnZW5lcmFsCmRhdGEgPC0gZmlsdGVyKGRhdGEsIEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiAhPSAnQ1JJU0lTIENPTVBMQUlOVCAtIEdFTkVSQUwnKQoKbW9ybmluZyA8LSBmaWx0ZXIoZGF0YSwgNiA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTAgKQptaWQuZGF5IDwtICBmaWx0ZXIoZGF0YSwgMTAgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDE0ICkKYWZ0ZXJub29uIDwtICBmaWx0ZXIoZGF0YSwgMTQgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDE4ICkKZXZlbmluZyA8LSAgZmlsdGVyKGRhdGEsIDE4IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAyMiApCm5pZ2h0IDwtICBmaWx0ZXIoZGF0YSwgMjIgPD0gYXRfc2NlbmVfdGltZV9ociB8IGF0X3NjZW5lX3RpbWVfaHIgPCAyICkKZWFybHkubW9ybmluZyA8LSAgZmlsdGVyKGRhdGEsIDIgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDYgKQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1vcm5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtaWQuZGF5LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYWZ0ZXJub29uLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZXZlbmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG5pZ2h0LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFybHkubW9ybmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKbGVuZ3RocyA8LSBjKG5yb3cobW9ybmluZyksIG5yb3cobWlkLmRheSksIG5yb3coYWZ0ZXJub29uKSwgbnJvdyhldmVuaW5nKSwgbnJvdyhuaWdodCksIG5yb3coZWFybHkubW9ybmluZykpCm5hbWVzIDwtIGMoJ01vcm5pbmdcbjY6MDAgLSA5OjU5JywgJ01pZC1kYXlcbjEwOjAwIC0gMTo1OScsICdBZnRlcm5vb25cbjI6MDAgLSA1OjU5JywgJ0V2ZW5pbmdcbjY6MDAgLSA5OjU5JywgJ05pZ2h0XG4xMDowMCAtIDE6NTknLCAnRWFybHkgTW9ybmluZ1xuMjowMCAtIDU6NTknKQpieS50b2QgPC0gZGF0YS5mcmFtZSgnVE9EJyA9IG5hbWVzLCAnQ291bnQuQ3JpbWVzJyA9IGxlbmd0aHMpCmJ5LnRvZCRUT0QgPSBmYWN0b3IoYnkudG9kJFRPRCwgbGV2ZWxzID0gYnkudG9kJFRPRCkKCmdncGxvdChieS50b2QsIGFlcyh4ID0gVE9ELCB5ID0gQ291bnQuQ3JpbWVzKSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAnaWRlbnRpdHknKQoKIyBmaW5kIHRoZSBtb2RlIG9mIG51bWVyaWMvY2hhcmFjdGVyIGRhdGEKTW9kZSA8LSBmdW5jdGlvbih4KSB7CiAgdXggPC0gdW5pcXVlKHgpCiAgdGFiIDwtIHRhYnVsYXRlKG1hdGNoKHgsIHV4KSk7IHV4W3RhYiA9PSBtYXgodGFiKV0KfQoKdG9kLm1lYW4gPC0gbWVhbihkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCnRvZC5tZWQgPC0gbWVkaWFuKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKdG9kLm1lYW4KdG9kLm1lZApNb2RlKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKCiNXaGF0IGlzIHRoZSBtb3N0IGNvbW1vbiBjcmltZSBjb21taXR0ZWQgYXQgZWFjaCBwZXJpb2Q/Ck1vZGUobW9ybmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUobWlkLmRheSRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoYWZ0ZXJub29uJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShldmVuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShuaWdodCRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoZWFybHkubW9ybmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCgojZml0IGttZWFucyBjbHVzdGVyaW5nIHRvIGVhY2ggdGltZSBwZXJpb2QuCm5yb3cobW9ybmluZykKZmluZC5udW0uY2x1c3RlcnMobW9ybmluZywgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobW9ybmluZywgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZmluZC5udW0uY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhtaWQuZGF5LCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpucm93KGFmdGVybm9vbikKZmluZC5udW0uY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhhZnRlcm5vb24sIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKGV2ZW5pbmcsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKGV2ZW5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKG5pZ2h0LCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhuaWdodCwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQpgYGAKCg==